package fi.lappalainen.geoapp.ui;

import fi.lappalainen.cachemanager.CacheManager;
import fi.lappalainen.cachemanager.Profile;
import fi.lappalainen.geoapp.utils.GeoCache;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Hashtable;

/**
 * Komentorivipohjaisen käyttölittymän toiminnot sisältävä luokka.
 * @author mika.j.lappalainen@gmail.com
 * @version 1.0
 * @since 1.0
 */
public class GeoAppUi {

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_MAIN -> päävalikko.
     */
    private static final int STATUS_MAIN = 1;

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_JOIN->GPX-tiedostojen liittäminen
     */
    private static final int STATUS_JOIN = 2;

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_COUNT->GPX-tiedoston sisältämien kätköjen laskeminen
     */
    private static final int STATUS_COUNT = 3;

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_FIND->Kätkön tietojen hakeminen
     */
    private static final int STATUS_FIND = 4;

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_LOG->kätkön lokkaaminen löydetyksi
     */
    private static final int STATUS_LOG = 5;

    /*
     * Satus kertoo missä toiminnossa ollaan menossa.
     * STATUS_EXIT->Sovelluksesta poistuminen
     */
    private static final int STATUS_EXIT = 6;

    /*
     * Alussa toiminto on päävalikko
     */
    private static int state = STATUS_MAIN;

    /*
     * Kätköjen käsittelystä huolehtiva olio.
     */
    private CacheManager manager;

    /**
     * Luo uuden käyttöliittymä olion
     * @param manager Kätköjen käsittelystä huolehtiva olio
     * @since 1.0
     */
    public GeoAppUi(CacheManager manager) {
        this.manager = manager;
    }

    /**
     * Kasittelee kayttajan valinnat
     * @param command
     * @since 1.0
     */
    public void handleMenuCommands(int command) {
        switch (command) {
            case 1:
                if (state == STATUS_MAIN) {
                    state = STATUS_JOIN;
                    handleMenuCommands(showJoinMenu());
                } else if (state == STATUS_JOIN) {
                    String sourcefolder = showGetFolder();
                    String destination = showGetFilename();
                    destination = sourcefolder + destination;
                    if (manager.joinCachesFromFolder(sourcefolder, destination)) {
                        state = STATUS_MAIN;
                        handleMenuCommands(showMainMenu());
                    } else {
                        this.showErrorinFileHandling();
                    }
                } else if (state == STATUS_FIND) {
                    GeoCache find = manager.findCacheById(showGetId());
                    this.showCacheDetails(find);
                }
                break;
            case 2:
                if (state == STATUS_MAIN) {
                    state = STATUS_COUNT;
                    int count = manager.countCachesInFile(showGetFilename());
                    this.showCacheCount(count);
                    handleMenuCommands(showMainMenu());
                } else if (state == STATUS_JOIN) {
                    String filenames = showGetFilenames();
                    String destination = showGetFilename();
                    manager.joinCachesByFilename(filenames, destination);
                    state = STATUS_MAIN;
                    handleMenuCommands(showMainMenu());
                } else if (state == STATUS_FIND) {
                }
                break;
            case 3:
                if (state == STATUS_MAIN) {
                    state = STATUS_FIND;
                    String filename = showGetFilename();
                    if (manager.readCachesFromFile(filename)) {
                        String[][] namesAndIds = manager.listNamesAndIds();
                        this.showCachesFound(namesAndIds);
                        handleMenuCommands(showFindIdOrNameMenu());
                    } else {
                        state = STATUS_MAIN;
                        showErrorinFileHandling();
                    }
                } else if (state == STATUS_JOIN) {
                    state = STATUS_MAIN;
                    handleMenuCommands(showMainMenu());
                }
                break;
            case 4:
                showLogYourFind();
                state = STATUS_MAIN;
                handleMenuCommands(showMainMenu());
                break;
            case 5:
                if (state == STATUS_MAIN) {
                    this.showListYourFinds();
                    handleMenuCommands(showMainMenu());
                } else {
                    state = STATUS_MAIN;
                    this.showWrongChoice();
                }
                break;
            case 6:
                System.out.print("Bye\n");
                return;
            default:
                System.out.print("Ei toteutettu\n");
                state = STATUS_MAIN;
                handleMenuCommands(showMainMenu());
                break;
        }
    }

    /*
     * Tulostaa naytolle sovelluksen ohjeet.
     * @since 1.0
     */
    private void showHelp() {
        System.out.print("***********************************\n");
        System.out.print("*GeoApp V 0.1                     *\n");
        System.out.print("*Tietoja sovelluksesta            *\n");
        System.out.print("***********************************\n");
    }

    /**
     * Tulostaa naytolle sovelluksen paavalikon ja jää
     * odottamaan kayttajan valintaa.
     * @return Kayttajan valinta
     * @since 1.0
     */
    public int showMainMenu() {
        System.out.print("***********************************\n");
        System.out.print("*Ohje                             *\n");
        System.out.print("*Valitse toimintoa vastaava numero*\n");
        System.out.print("***********************************\n");
        System.out.print("1. Yhdistä GPX-tiedostoja\n");
        System.out.print("2. Laske GPX-tiedoston sisältämät kätköt\n");
        System.out.print("3. Hae kätkön tiedot\n");
        System.out.print("4. Lokkaa kätkö\n");
        System.out.print("5. Listaa löytämäsi kätköt\n");
        System.out.print("6. Poistu ohjelmasta\n");
        System.out.print("\n");
        System.out.print("Valintasi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return Integer.parseInt(choise);
    }

    /*
     * Tulostaa naytolle GPX-tiedostojen liittamisen vaihtoehdot
     * ja jaa odottamaan kayttajan valintaa
     * @return kayttajan valinta
     * @since 1.0
     */
    private int showJoinMenu() {
        System.out.print("***********************************\n");
        System.out.print("*Ohje                             *\n");
        System.out.print("*Valitse toimintoa vastaava numero*\n");
        System.out.print("***********************************\n");
        System.out.print("1. Yhdistä kansiosta\n");
        System.out.print("2. Nimen perusteella\n");
        System.out.print("3. Palaa aloitusvalikkoon\n");
        System.out.print("Valintasi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return Integer.parseInt(choise);
    }

    /*
     * Jos käyttäjän on antanut virheellisen kansion nimen tulostetaan
     * näytölle vaihtoehdot joko kansion nimen uudelleen antamiseen tai
     * päävalikkoon palaamiseen.
     * @return Käyttäjän valitsema valinta.
     */
    private int showFolderNotFound() {
        System.out.print("***********************************");
        System.out.print("*Ohje                             *");
        System.out.print("*Valitse toimintoa vastaava numero*");
        System.out.print("***********************************");
        System.out.print("1. Anna tiedoston tai kansion nimi uudestaan");
        System.out.print("2. Palaa aloitusvalikkoon");
        System.out.print("Valintasi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return Integer.parseInt(choise);
    }

    /*
     * Tulostaa kansion kyselyn näytölle.
     * @return Kansion nimi
     */
    private String showGetFolder() {
        System.out.print("Anna kansion nimi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return choise;
    }

    /*
     * Tulostaa tiedoston nimen kyselyn.
     * @return Tiedoston nimi.
     * @since 1.0
     */
    private String showGetFilename() {
        System.out.print("Anna tiedoston nimi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return choise;
    }

    /*
     * Tulostaa tiedostojen nimien kyselyn näytölle.
     * @return Tiedostojen nimet merkijonona erottimena ","
     * @since 1.0
     */
    private String showGetFilenames() {
        System.out.print("Anna tiedostojen nimet, erottimena ;>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return choise;
    }

    /**
     * Tulostaa kätkön lokkaus näytön.
     * @since 1.0
     */
    private void showLogYourFind() {
        System.out.print("Anna katkoilija tunnuksesi>");
        String name = null;
        try {
            name = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        Profile p = null;
        try {
            p = new Profile(name);
        } catch (IOException ex) {
            System.out.println("Profiilia ei voitu luoda/avata");
        }
        System.out.print("Anna katkon koodi>");
        String cacheCode = null;
        try {
            cacheCode = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        System.out.print("Anna löytöpäivä muodossa pp.kk.vvvv>");
        String findDate = null;
        try {
            findDate = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        if(p.addNewFind(cacheCode, findDate)) {
        p.save();
        } else {
            showLoggingFailed();
        }
    }

    /*
     * Tulostaa kätköjen määrän näytölle.
     * @param count Kätköjen määärä.
     * @since 1.0
     */
    private void showCacheCount(int count) {
        System.out.print("Kätköjä löytyi " + count + "\n");
    }

    /**
     * Tulostaa näytölle käyttäjän löytämät kätköt.
     * @param namesAndIds merkkijono taulukko, jossa löydetyt kätköt.
     * Ensimmäisessä sarakeessa ID, ja toisessa löytöpäivämäärä.
     * @since 1.0
     */
    private void showCachesFound(String[][] namesAndIds) {
        for (int idx = 0; idx < namesAndIds.length; idx++) {
            System.out.println(namesAndIds[idx][0] + " " + namesAndIds[idx][1]);
        }
    }

    /*
     * Tulostaa näytön kätkönen etsimiseen
     * @return Käyttäjän valinta
     * @since 1.0
     */
    private int showFindIdOrNameMenu() {
        System.out.println("***********************************");
        System.out.println("*Ohje                             *");
        System.out.println("*Valitse toimintoa vastaava numero*");
        System.out.println("***********************************");
        System.out.println("1. Näytetään tiedot ID:n perusteella");
        System.out.println("2. Näytetään tiedot Nimen perusteella");
        System.out.println("Valintasi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return Integer.parseInt(choise);
    }

    /**
     * Tulostaa näytölle kätkön ID:n kyselyn
     * @return Kätkön ID
     * @since 1.0
     */
    private String showGetId() {
        System.out.print("Anna kätkön id>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return choise;
    }

    /*
     * Tulostaa näytölle kätkön nimen kyselyn.
     * @return Kätkön nimi
     * @since 1.0
     */
    private String showGetName() {
        System.out.print("Anna kätkön nimi>");
        String choise = null;
        try {
            choise = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        return choise;
    }

    /*
     * Tulostaa näytölle kätkön tiedot.
     * @param cache Tulostettava kätkö
     * @since 1.0
     */
    private void showCacheDetails(GeoCache cache) {
        System.out.println(cache.getId());
        System.out.println(cache.getName());
        System.out.print(cache.getDifficulty() + " ");
        System.out.println(cache.getTerrain());
        System.out.println("");
        System.out.println(cache.getShortDescription());
        System.out.println("");
        System.out.println(cache.getLongDescription());
    }

    /*
     * Tulostaa näytölle kätköilijän löytämät kätköt.
     * @since 1.0
     */
    private void showListYourFinds() {
        System.out.print("Anna katkoilija tunnuksesi>");
        String name = null;
        try {
            name = (new BufferedReader(new InputStreamReader(System.in))).readLine();
        } catch (IOException ex) {
            System.out.print(ex);
        }
        Profile p = null;
        try {
            p = new Profile(name);
        } catch (IOException ex) {
            System.out.println("Profiilia ei voitu avata/luoda");
        }
        Hashtable finds = p.getFinds();
        for (Enumeration e = finds.keys(); e.hasMoreElements();) {
            String key = (String) e.nextElement();
            String loggedDate = (String) finds.get(key);
            System.out.print(key);
            System.out.print(" ");
            System.out.println(loggedDate);
        }
    }

    private void showErrorinFileHandling() {
        System.out.println("***********************************");
        System.out.println("*Tiedostonkäsittelyssä ongelmia!!!*");
        System.out.println("***********************************");
        state = STATUS_MAIN;
        handleMenuCommands(showMainMenu());
    }

    private void showWrongChoice() {
        System.out.println("***********************************");
        System.out.println("*Väärä valinta!!!                 *");
        System.out.println("***********************************");
        state = STATUS_MAIN;
        handleMenuCommands(showMainMenu());
    }

    private void showLoggingFailed() {
        System.out.println("***********************************");
        System.out.println("*Löydön lisäämien epäonnistui     *");
        System.out.println("***********************************");
        state = STATUS_MAIN;
        handleMenuCommands(showMainMenu());
    }
}
